package com.thd.springboottest.security.securitycustom;

import com.thd.springboottest.security.constants.LoginType;
import org.springframework.lang.Nullable;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * com.thd.springboottest.security.securitycustom.MyFilter
 *
 * @author: wanglei62
 * @DATE: 2022/6/22 15:25
 **/
public class ThirdFilter extends AbstractAuthenticationProcessingFilter {

    public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
    public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";

    // 用户名/电话/邮箱
    private String userKeyParameter = "userKey";
    // 用户密码/电话验证码/邮箱验证码
    private String validatecodeParameter = "validatecode";
    // 是否只处理post请求
    private boolean postOnly = true;

    // 手机登录的提交请求地址
    public ThirdFilter() {
        super(new AntPathRequestMatcher("/thirdLogin", "GET"));
    }

    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
//        if (this.postOnly && !request.getMethod().equals("POST")) {
//            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
//        } else {
            String userKey = this.obtainUserKey(request);
            String validateCode = this.obtainValidateCode(request);
            if (userKey == null) {
                userKey = "";
            }
            if (validateCode == null) {
                validateCode = "";
            }
            userKey = userKey.trim();

            // 新增多种登录方式的逻辑
            String loginMethod = this.obtainLoginMethod(request);
            AbstractAuthenticationToken authRequest = null;

            try{
                switch(loginMethod) {
                    // 此处可以扩展多种登录形式,例如用户名密码登录,短信验证码登录,邮件验证码登录...
                    case "USERNAMEPASSWORD":
                        authRequest = new ThirdToken(userKey, validateCode, LoginType.USERNAMEPASSWORD.name());
                        break;
                    case "MOBILEVALIDATECODE":
                        authRequest = new ThirdToken(userKey, validateCode, LoginType.MOBILEVALIDATECODE.name());
                        break;
                    default:
                        authRequest = new ThirdToken(userKey, validateCode,LoginType.MOBILEVALIDATECODE.name());
                        break;
                }
            }catch (Exception e){
                authRequest = new ThirdToken(userKey, validateCode);
            }


            // 将请求的信息一并放到token中
            this.setDetails(request, authRequest);
            // 对用户进行认证
            return this.getAuthenticationManager().authenticate(authRequest);
//        }
    }

    @Nullable
    protected String obtainValidateCode(HttpServletRequest request) {
        return request.getParameter(this.validatecodeParameter);
    }

    @Nullable
    protected String obtainUserKey(HttpServletRequest request) {
        return request.getParameter(this.userKeyParameter);
    }

    protected String obtainLoginMethod(HttpServletRequest request) {
        String headerLoginType = request.getHeader("loginType");
        String requestParameterLoginType = request.getParameter("loginType");
        if(!StringUtils.isEmpty(headerLoginType)){
            return headerLoginType;
        }
        if(!StringUtils.isEmpty(requestParameterLoginType)){
            return requestParameterLoginType;
        }
        return LoginType.MOBILEVALIDATECODE.name();
    }

    protected void setDetails(HttpServletRequest request, AbstractAuthenticationToken authRequest) {
        authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
    }

    public void setUserKeyParameter(String userKeyParameter) {
        Assert.hasText(userKeyParameter, "userKey parameter must not be empty or null");
        this.userKeyParameter = userKeyParameter;
    }

    public void setValidateCodeParameter(String validatecodeParameter) {
        Assert.hasText(validatecodeParameter, "validate code parameter must not be empty or null");
        this.validatecodeParameter = validatecodeParameter;
    }

    public void setPostOnly(boolean postOnly) {
        this.postOnly = postOnly;
    }

    public final String getUserKeyParameter() {
        return this.userKeyParameter;
    }

    public final String getValidateCodeParameter() {
        return this.validatecodeParameter;
    }
}
